﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Bowerbird.Website.Models;
using Bowerbird.Api.Dtos;

namespace Bowerbird.Website.Controllers
{
    public class ControllerBase : Controller
    {
        public static string CURRENT_USER_SESSION_KEY = "CURRENT_USER_SESSION_KEY";
        protected static string IDENTITY_PROVIDER_CLAME_TYPE = @"http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider";
        protected static string NAME_IDENTIFIER_CLAME_TYPE = @"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
        protected static string NAME_CLAIM_TYPE = @"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";
        protected static string EXPIRATION_CLAIM_TYPE = @"http://schemas.microsoft.com/ws/2008/06/identity/claims/expiration";
        protected static string EMAIL_ADDRESS_CLAIM_TYPE = @"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
        protected static string ACCESS_TOKEN_CLAIM_TYPE = @"http://www.facebook.com/claims/AccessToken";

        protected override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            ViewBag.CurrentUser = CurrentUser;

            base.OnActionExecuting(filterContext);
        }

        protected UserModel CurrentUser
        {
            get
            {
                if (Request.IsAuthenticated)
                {
                    UserModel currentUser = Session[CURRENT_USER_SESSION_KEY] as UserModel;

                    if (currentUser == null)
                    {
                        Claims claims = TryReadClaims();

                        User user = ApiWrapper.LogIn(claims.IdentityProvider, claims.NameIdentifier, claims.Name);

                        if (user != null)
                        {
                            currentUser = new UserModel
                            {
                                Id = user.id,
                                IdentityProvider = user.identityProvider,
                                NameIdentifier = user.nameIdentifier,
                                IsAuthenticated = true,
                                Name = user.name,
                                Email = user.email,
                                ProfilePictureUrl = user.profilePicture ?? Url.Content("~/Content/user.png")
                            };

                            Session[CURRENT_USER_SESSION_KEY] = currentUser;
                        }
                    }

                    ViewBag.CurrentUser = currentUser;
                    return currentUser;
                }
                else
                {
                    Session[CURRENT_USER_SESSION_KEY] = null;
                }

                ViewBag.CurrentUser = null;
                return null;
            }
            set
            {
                Session[CURRENT_USER_SESSION_KEY] = value;

                ViewBag.CurrentUser = value;
            }
        }

        protected Claims TryReadClaims()
        {
            Claims claims = new Claims();

            var identity = (Microsoft.IdentityModel.Claims.ClaimsIdentity)User.Identity;

            // Identity Provider
            var claim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(IDENTITY_PROVIDER_CLAME_TYPE));
            if (claim != null)
                claims.IdentityProvider = claim.Value;
            else
                throw new UnauthorizedAccessException("Cannot read IdentityProvider claim.");

            // Name Identifier
            claim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(NAME_IDENTIFIER_CLAME_TYPE));
            if (claim != null)
                claims.NameIdentifier = claim.Value;
            else
                throw new UnauthorizedAccessException("Cannot read NameIdentifier claim.");

            // Name
            claim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(NAME_CLAIM_TYPE));
            if (claim != null)
                claims.Name = claim.Value;

            // Email Address
            claim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(EMAIL_ADDRESS_CLAIM_TYPE));
            if (claim != null)
                claims.Email = claim.Value;

            // Access Token
            claim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(ACCESS_TOKEN_CLAIM_TYPE));
            if (claim != null)
                claims.AccessToken = claim.Value;

            // Expiration
            claim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(EXPIRATION_CLAIM_TYPE));
            if (claim != null)
                claims.Expiration = claim.Value;

            return claims;
        }

        protected struct Claims
        {
            public string IdentityProvider { get; set; }
            public string NameIdentifier { get; set; }
            public string Name { get; set; }
            public string Email { get; set; }
            public string AccessToken { get; set; }
            public string Expiration { get; set; }
        }
    }
}
